<?php

namespace app\backend\services\auth;

/**
 * 权限认证类
 *
 * Class Auth
 *
 * @package auth
 * Author: zsw zswemail@qq.com
 */
class Authority
{

    /**
     * 所有权限
     *
     * @var array<Permission>
     */
    protected $permissions = [];

    /**
     * 权限
     *
     * @var array<Permission>
     */
    protected $permissionsList = [];

    /**
     * 已授权权限
     *
     * @var null|array<Permission>
     */
    protected $authorizedPermissionsList = [];

    /**
     * 超级管理员
     * 不校验权限
     *
     * @var bool
     */
    protected $administrator = false;

    /**
     * @var UserInterface
     */
    protected $user;

    /**
     * @var array<RoleInterface>
     */
    protected $roles = [];

    /**
     * @var string
     */
    protected $error = '';

    /**
     * 加入权限
     *
     * @param array           $permissions
     * @param Permission|null $parent
     * @param bool            $main
     *
     * @return array
     */
    public function addPermissions(array $permissions, ?Permission $parent = null, $main = true): array
    {
        $data = [];
        foreach ($permissions as $permission)
        {
            if ( ! isset($permission['route']) && ! isset($permission['name']))
            {
                $data[] = $this->addPermissions($permission, $parent, false);
                continue;
            } elseif ( ! $permission instanceof Permission )
            {
                $permission = new Permission($permission, $parent);
                if (is_array($permission->children))
                {
                    $permission->addChildren($this->addPermissions($permission->children, $permission, false));
                }
            }
            array_push($data, $permission);
            $main && array_push($this->permissions, $permission);
            $this->addPermissionList($permission);
        }

        return $data;
    }

    /**
     * 索引路由
     *
     * @param Permission $permission
     */
    protected function addPermissionList(Permission $permission)
    {
        $this->permissionsList[$permission->route] = $permission;
    }


    /**
     * 判断当前用户权限
     * 如果出现多个相同路由 满足一个就通过
     *
     * @param string | array $route
     *
     * @return bool
     */
    public function can( $route ): bool
    {
        $permission = $this->getPermissionList(is_array($route) ? $route['route'] : $route);

        return $permission && $permission->check($route, $this);
    }

    /**
     * 获取所有规则树状
     *
     * @return array
     */
    public function getPermissions(): array
    {
        return $this->permissions;
    }

    /**
     * 规则列表
     *
     * @param string $route
     *
     * @return Permission | array<Permission>
     */
    public function getPermissionList($route = null)
    {
        return is_null($route) ? $this->permissionsList : $this->permissionsList[$route] ?? null;
    }

    /**
     * 是否授权
     *
     * @param Permission $permission
     *
     * @return bool
     */
    public function isAuthorized(Permission $permission): bool
    {
        return $this->isAdministrator() ?: in_array($permission, $this->authorizedPermissionsList());
    }

    /**
     * 分派角色
     *
     * @param RoleInterface|array<RoleInterface> $roles
     *
     * @return $this
     */
    public function assignRole($roles): self
    {
        if (is_array($roles))
        {
            foreach ($roles as $role)
            {
                $this->assignRole($role);
            }
        } else
        {
            if ($roles instanceof RoleInterface)
            {
                $this->roles[] = $roles;
            }
        }

        $this->authorizedPermissionsList = [];

        return $this;
    }

    protected function authorizedPermissionsList($route = null)
    {
        is_null($this->authorizedPermissionsList) && $this->authorize();
        return is_null($route) ? $this->authorizedPermissionsList : $this->authorizedPermissionsList[$route] ?? null;
    }

    /**
     * 授权角色权限
     *
     * @return array
     */
    protected function authorize()
    {
        $roles = $this->roles();

        $permissions = [];
        /** @var RoleInterface $role */
        foreach ($roles as $role)
        {
            $routes = $role->permissions();
            foreach ($routes as $route)
            {
                $permission = $this->getPermissionList($route);
                foreach ($permission as $p) {
                    $this->addAuthorizePermissionList($p);
                }
            }
        }

        return $permissions;
    }

    /**
     * 添加授权索引
     *
     * @param Permission $permission
     */
    private function addAuthorizePermissionList(Permission $permission)
    {
        $this->authorizedPermissionsList[$permission->route] = $permission;
    }

    /**
     * 获取角色
     *
     * @return array<RoleInterface>
     */
    public function roles(): array
    {
        return $this->roles;
    }

    /**
     * 错误
     *
     * @return string
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * 设置当前超级管理员
     *
     * @param bool $value
     *
     * @return $this
     */
    public function administrator(bool $value = true): self
    {
        $this->administrator = $value;
        return $this;
    }

    /**
     * @return bool
     */
    public function isAdministrator(): bool
    {
        return $this->administrator;
    }

    /**
     * 用户
     *
     * @return UserInterface
     */
    public function user()
    {
        return $this->user;
    }

    /**
     * 设置用户
     *
     * @param UserInterface $user
     *
     * @return $this
     */
    public function setUser(UserInterface $user): self
    {
        $this->user = $user;
        return $this;
    }

    /**
     * 游客
     *
     * @return bool
     */
    public function guest(): bool
    {
        return !$this->user;
    }

}
